## Магический метод `__bool__` определения правдивости объектов

Что такое правдивость? 
Это когда к экземпляру явно или неявно применяется функция bool(). 

С ней мы с вами уже знакомы и применяли к обычным типам данных:

```python
bool(123)
bool(-1)
bool(0)
bool("python")
bool("")
bool([])
```
В стандартном поведении она возвращает `True` для непустых объектов и `False` – для пустых.

Давайте посмотрим, что она будет выдавать для экземпляров классов. 

```python
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
```
Создадим его объект:
```python
p = Point(3, 4)
```
и применим к нему функцию bool():
```python
print(bool(p))
```

Увидим значение `True`.

В действительности, эта функция всегда возвращает `True` для любых объектов пользовательского класса. 

Получается, что смысла в ней особого нет, применительно к экземплярам наших классов? 

Не совсем. Мы можем переопределить ее поведение либо через магический метод `__len__()`, либо через метод `__bool__()`:

`__len__()` – вызывается функцией `bool()`, если не определен магический метод `__bool__()`;
`__bool__()` – вызывается в приоритетном порядке функцией bool().

Вначале я пропишу магический метод `__len__()` в классе `Point`, следующим образом:

```python
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
 
    def __len__(self):
        print("__len__")
        return self.x * self.x + self.y * self.y
```
В этом методе я вычисляю и возвращаю квадрат длины радиус-вектора с координатами (x; y). 

Запустим программу и видим значение `True`, а также сообщение `«__len__»`. 

То есть, действительно был вызван метод `__len__()` и, так как он вернул не нулевое значение, то функция bool() интерпретировала его как `True`.

Давайте в экземпляре класса пропишем нулевые координаты, чтобы длина вектора была нулевой:

```python
p = Point(0, 0)
```
Теперь видим ожидаемое значение `False`.

Конечно, если нам нужно явно описать алгоритм работы функции `bool()` применительно к нашим экземплярам класса, то следует использовать магический метод `__bool__()`. 

Я запишу его в таком виде:

```python
    def __bool__(self):
        print("__bool__")
        return self.x == self.y
```
Теперь, объект будет считаться правдивым (истинным), если его координаты равны. Запускаем программу и видим, что для нулей отображается значение `True`. 

Если же прописать не равные координаты:

```python
p = Point(10, 20)
```
то получаем значение `False`. 

Конечно, такая реализация магического метода `__bool__()` – это лишь учебный пример, чтобы вы поняли принцип его работы. 

В реальности, мы можем в этом методе прописывать любую логику. 

Единственное условие, чтобы данный метод возвращал булево значение `True` или `False`. 

Указывать в операторе `return` другие типы данных запрещено.

Все это хорошо, но где это используется? 

Чаще всего в условных конструкциях. Например, если прописать вот такое условие:

```python
if p:
    print("объект p дает True")
else:
    print("объект p дает False")
```

Здесь происходит неявный вызов функции `bool()` при проверке условия. 

Поэтому в программах, где требуется описать собственные проверки истинности или ложности объектов, то пользуются или магическим методом `__len__()`, но чаще всего, магическим методом `__bool__()`.